﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kokomo.Environment;
using System.Reflection;
using System.Collections;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;

namespace Kokomo.PeInspector.Reflection
{
	[ViewType(typeof(TypeMembersView))]
	class TypeMembersViewModel : SearchViewModel<TypeMemberItem>
	{
		public Type Type { get; private set; }
		public IMetadataHost Host { get; private set; }

		public TypeMembersViewModel(
			Type type,
			IMetadataHost host,
			ICommand navigateToCommand
			)
		{
			if (type == null) throw new ArgumentNullException("type");
			if (host == null) throw new ArgumentNullException("host");

			this.Type = type;
			this.Host = host;
			this.NavigateToCommand = navigateToCommand;

			this.LoadMemberItems();
		}

		public ICommand NavigateToCommand { get; private set; }

		#region Members
		private IEnumerable<TypeMemberItem> _memberItems;

		protected virtual void LoadMemberItems()
		{
			this._memberItems = this.GetMemberItems();
			this.InvalidateSearch();
		}

		public bool IncludeHiddenMembers
		{
			get { return AssemblyAnalyzerEditor.ViewSettings.IncludeHiddenTypeMembers; }
			set
			{
				AssemblyAnalyzerEditor.ViewSettings.IncludeHiddenTypeMembers = value;
				this.OnIncludeHiddenMembersChanged();
			}
		}
		protected virtual void OnIncludeHiddenMembersChanged()
		{
			this.OnPropertyChanged("IncludeHiddenMembers");
			this.LoadMemberItems();
		}

		public bool GroupMembersByType
		{
			get { return AssemblyAnalyzerEditor.ViewSettings.GroupTypeMembers; }
			set
			{
				AssemblyAnalyzerEditor.ViewSettings.GroupTypeMembers = value;
				this.OnGroupMembersByTypeChanged();
			}
		}
		protected virtual void OnGroupMembersByTypeChanged()
		{
			this.ApplyMemberGrouping(this.Results);
			this.OnPropertyChanged("GroupMembersByType");
		}
		private void ApplyMemberGrouping(IEnumerable<TypeMemberItem> results)
		{
			if (results != null)
			{
				ICollectionView view = CollectionViewSource.GetDefaultView(results);
				view.GroupDescriptions.Clear();
				if (this.GroupMembersByType)
				{
					view.GroupDescriptions.Add(new PropertyGroupDescription("MemberType"));
				}
			}
		}

		private IEnumerable<TypeMemberItem> GetMemberItems()
		{
			BindingFlags flags = BindingFlags.DeclaredOnly
				| BindingFlags.Public | BindingFlags.NonPublic
				| BindingFlags.Static | BindingFlags.Instance
				;

			MemberInfo[] members = this.Type.GetMembers(flags).OrderBy(m => m.Name).ToArray();

			List<TypeMemberItem> items = new List<TypeMemberItem>();
			foreach (var member in members)
			{
				if (this.IncludeHiddenMembers || !member.IsHiddenClassMember())
				{
					TypeMemberItem item = new TypeMemberItem(member, MemberViewInfo.GetMemberViewInfo(member));
					items.Add(item);
				}
			}

			return items;
		}
		#endregion

		#region Search
		protected override IEnumerable<TypeMemberItem> OnSearchAsync(string searchTerm, int searchVersion)
		{
			if (string.IsNullOrEmpty(searchTerm))
			{
				return this._memberItems;
			}
			else
			{
				List<TypeMemberItem> results = new List<TypeMemberItem>();
				foreach (var memberItem in this._memberItems)
				{
					if (this.SearchVersion != searchVersion) return null;

					if (memberItem.MemberName.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase))
						results.Add(memberItem);
				}

				return results;
			}
		}
		protected override void OnResultsChanging(IEnumerable<TypeMemberItem> results)
		{
			this.ApplyMemberGrouping(results);
		}
		#endregion
	}
}
